
/*========================================================================================
 *                                                                                      *
 *               Copyright(c) 2013-2014, Cha SangWoo, All rights reserved.              *
 *                                                                                      *
 * This file is part of ChaOS.                                                          *
 *                                                                                      *
 * Permission to use, copy, modify, and distribute this software in source and binary   *
 * forms and its documentation for any purpose and without fee is hereby granted,       *
 * provided that the above copyright notice appear in all copies and that both that     *
 * copyright notice and this permission notice appear in supporting documentation.      *
 *                                                                                      *
 * THIS SOFTWARE IS PROVIDED BY THE CHA SANGWOO AND CONTRIBUTORS "AS IS" AND ANY        *
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED            *
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.   *
 * IN NO EVENT SHALL CHA SANGWOO OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,    *
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT         *
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,          *
 * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF            *
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE      *
 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,                    *
 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.                                   *
 *                                                                                      *
========================================================================================*/

#include "co_core.h"
#include "co_byte_pool.h"

#if (FLAG_USE_CHAOS_BYTE_POOL == CO_ENABLE)

#ifdef __cplusplus
    namespace ChaOS {
#endif

//////////////////////////////////////  < BEGIN >  ///////////////////////////////////////

/*======================================================================================*/
/*
    @fn             OBJECT co_byte_pool_create(UINT size, UINT count)

    @brief          

    @param [in]     size  - 
    @param [in]     count - 

    @return         Object for byte pool.
*/
/*======================================================================================*/
OBJECT co_byte_pool_create(UINT size, UINT count)
{
    UINT8          *pdata;
    BYTE_POOL_CB   *ppool;
    POOL_BLOCK_CB  *pblock;
    UINT            total_size;

    CO_ASSERT(size > 0);
    CO_ASSERT(count > 0);

    // get allocation size
    size  += sizeof(POOL_BLOCK_CB) - sizeof(UINT32);
    total_size  = size;
    total_size *= count;
    total_size += sizeof(BYTE_POOL_CB);

    // allocate heap memory
    pdata = (UINT8*) co_heap_alloc(total_size);
    CO_ASSERT(pdata);

    // set object ID
    ppool = (BYTE_POOL_CB*) pdata;
    OBJID_SET(ppool, OBJ_BYTE_POOL_ID);

    ppool->pfree = NULL;

    // initialize blocks
    pdata += sizeof(BYTE_POOL_CB);
    for (total_size = 0; total_size < count; total_size++)
    {
        pblock = (POOL_BLOCK_CB*) pdata;

        // set object id
        OBJID_SET(pblock, OBJ_POOL_BLOCK_ID);

        // set object of byte pool
        pblock->objPool = (OBJECT) ppool;

        // add free list in byte pool
        pblock->pnext = ppool->pfree;
        ppool->pfree = pblock;

        pdata += size;
    }

    return (OBJECT) ppool;
}


/*======================================================================================*/
/*
    @fn             BOOL co_byte_pool_get(OBJECT object, VOID **pdata, UINT16 timeout)

    @brief          

    @param [in]     object  - 
    @param [in]     pdata   - 

    @return         Object for byte pool.
*/
/*======================================================================================*/
BOOL co_byte_pool_get(OBJECT object, VOID **pdata)
{
    BYTE_POOL_CB   *ppool = (BYTE_POOL_CB*) object;
    POOL_BLOCK_CB  *pblock;

    // check object ID
    OBJID_CHECK(ppool, OBJ_BYTE_POOL_ID);

    ///////////////////
    CO_ENTER_CRITICAL();

    if (ppool->pfree)
    {
        pblock = ppool->pfree;

        // check object ID
        OBJID_CHECK(pblock, OBJ_POOL_BLOCK_ID);

        ppool->pfree = pblock->pnext;
        pblock->pnext = NULL;

        *pdata = (void*)pblock->data;

        CO_LEAVE_CRITICAL();
        ////////////////////

        return TRUE;
    }
    else
    {
        CO_LEAVE_CRITICAL();
        ////////////////////

        return FALSE;
    }
}


/*======================================================================================*/
/*
    @fn             VOID co_byte_pool_put(OBJECT object, VOID *pdata)

    @brief          

    @param [in]     pdata - 

    @return         None
*/
/*======================================================================================*/
VOID co_byte_pool_put(VOID *pdata)
{
    BYTE_POOL_CB   *ppool;
    POOL_BLOCK_CB  *pblock;

    CO_ASSERT(pdata);

    // check object ID
    pblock = CASTING_OF(POOL_BLOCK_CB, data, pdata);
    OBJID_CHECK(pblock, OBJ_POOL_BLOCK_ID);

    // check object ID
    ppool  = (BYTE_POOL_CB*) pblock->objPool;
    OBJID_CHECK(ppool, OBJ_BYTE_POOL_ID);

    CO_ASSERT(pblock->pnext == NULL);

    ///////////////////
    CO_ENTER_CRITICAL();

    pblock->pnext = ppool->pfree;
    ppool->pfree = pblock;

    CO_LEAVE_CRITICAL();
    ////////////////////
}

//////////////////////////////////////  <  END  >  ///////////////////////////////////////

#ifdef __cplusplus
    } /* namespace ChaOS */
#endif

#endif // (FLAG_USE_CHAOS_BYTE_POOL == CO_ENABLE)

